﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Microsoft.Reporting.WinForms;

using EdgeStatz.ESSystems.Objects;
using EdgeStatz.ESSystems.Logs;
using EdgeStatz.ModelEngine.DatabaseTools;
using EdgeStatz.ModelEngine.FolderTools;
using EdgeStatz.ModelEngine.FormTools;
using EdgeStatz.ModelEngine.ReportTools;

namespace EdgeStatz
{
    public partial class EdgeStatz : Form
    {
        private DBStructureEngine databaseEngine;
        private FolderEngine folderEngine;
        private FormEngine formEngine;
        private ReportEngine reportEngine;

        public EdgeStatz()
        {
            InitializeComponent();
            CheckRegistry();
            SetControlsState(false);
        }
        
        public EdgeStatz(string filename)
            : this()
        {
            LoadModelFile(filename);
        }

        #region Registry Settings
        private void CheckRegistry()
        {            
            GlobalRegistrySettings.Load();
            List<string> filepaths = new List<string> { };
            List<string> filenames = new List<string> { };
            this.recentToolStripMenuItem.DropDownItems.Clear();
            if (GlobalRegistrySettings.ModelCount > 0)
            {
                recentToolStripMenuItem.Enabled = true;
                
                filepaths.AddRange(GlobalRegistrySettings.ModelPaths);
                filenames.AddRange(GlobalRegistrySettings.ModelNames);
                for (int i = 0; i < filenames.Count; i++)
                {
                    ToolStripItem tsi = new ToolStripMenuItem(filenames[i]);
                    tsi.Click += new EventHandler(
                        delegate(object sender, EventArgs e)
                        {
                            if (GlobalSystemSettings.ModelFilePath != null)
                                closeToolStripMenuItem_Click(null, e);

                            LoadModelFile(filepaths[filenames.IndexOf(sender.ToString())]);                         
                        });

                    this.recentToolStripMenuItem.DropDownItems.Add(tsi);
                }
            }
            else
            {
                recentToolStripMenuItem.Enabled = false;
            }            
        }
        #endregion

        #region OpenFile
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (GlobalSystemSettings.ModelFilePath != null)
                closeToolStripMenuItem_Click(null, e);

            OpenFileDialog ofdialog = new OpenFileDialog();
            ofdialog.Title = "Open Model File";
            ofdialog.Filter = "EdgeStatz Model|*.esm|XML|*.xml|All files|*.*";
            ofdialog.Multiselect = false;
            if (ofdialog.ShowDialog() == DialogResult.OK)
                LoadModelFile(ofdialog.FileName);
        }
        
        private void LoadModelFile(string filename)
        {
            try
            {
                GlobalSystemSettings.ModelFilePath = filename;

                databaseEngine = new DBStructureEngine(GlobalSystemSettings.ModelFilePath);

                GlobalSystemSettings.DatabaseName = databaseEngine.DatabaseName;
                GlobalSystemSettings.ModelName = databaseEngine.ModelName;
                GlobalSystemSettings.SystemFolderPath = databaseEngine.ModelPath;
                GlobalSystemSettings.LogSql = databaseEngine.Options_LogSql;
                LogWriter.SetFilePath(GlobalSystemSettings.SystemFolderPath);

                formEngine = new FormEngine(GlobalSystemSettings.ModelFilePath);
                folderEngine = new FolderEngine(GlobalSystemSettings.ModelFilePath);
                reportEngine = new ReportEngine(GlobalSystemSettings.ModelFilePath);

                Provider prov = GetProvider();
                if (prov == null)
                {
                    closeToolStripMenuItem_Click(null, null);
                    throw new NullReferenceException();
                }
                GlobalObjectsSQL.SetConnectionString(prov);
                if (databaseEngine.Options_EmailServer != null)
                    Email.Server = databaseEngine.Options_EmailServer;

                formEngine.LoadExistingAssembly();

                GlobalRegistrySettings.CreateNewModelKey(databaseEngine.ModelName, filename);
                CheckRegistry();
            }
            catch (Exception ex)
            {
                MessageBox.Show("An " + ex.GetType().Name + " occured while loading the file {" + filename + "}.\n\n" + ex.Message,
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            SetControlsState(true);
            if (!databaseEngine.CheckDatabaseExists())
            {
                Label lbl = new Label();
                lbl.Text = "The Database doesn't exist or cannot be found.\nTo create a new one please go to Tools > Options.\n" +
                    "From the Database options select Update.";
                lbl.AutoSize = true;
                splitContainer1.Panel2.Controls.Clear();
                splitContainer1.Panel2.Controls.Add(lbl);
                return;

            }            
            RefreshTreeNodes();
            RefreshReports();
            //splitContainer1.Panel2.Controls.Clear();
        }

        private Provider GetProvider()
        {
            Provider provider = databaseEngine.GetDefaultProvider();;
            while (!GlobalObjectsSQL.TestConnection(provider))
            {
                GetProviders getProv = new GetProviders(databaseEngine.GetProviders());
                if(provider == null)
                    getProv.Message = "No providers have been set.";
                else
                    getProv.Message = "Connection to " + provider.Name + " has failed.";
                if (getProv.ShowDialog() == DialogResult.OK)
                {
                    provider = getProv.Selection;
                    provider.Database = databaseEngine.DatabaseName;
                    databaseEngine.SetProviders(getProv.Providers);
                    databaseEngine.SaveChanges();
                }
                else
                {
                    return null;
                }
            }
            return provider;
        }

        private void RefreshTreeNodes()
        {
            treeView_Folders.Nodes.Clear();
            object[] a = folderEngine.GetLevelOneFolders();
            object[] b = folderEngine.GetLevelTwoFolders();
            List<object> e = new List<object> { };
            e.AddRange(a);
            e.AddRange(b);

            TreeNode tn_folder = null;
            foreach (object c in e.ToArray())
            {
                if (c.GetType().Equals(typeof(string)))
                {
                    tn_folder = new TreeNode();
                    tn_folder.Name = (string)c;
                    tn_folder.Text = (string)c;
                    tn_folder.ImageIndex = 0;
                    tn_folder.SelectedImageIndex = 0;
                }
                else if (c.GetType().Equals(typeof(FolderObj[])))
                {
                    object[] f1 = (object[])c;
                    foreach (object d in f1)
                    {
                        FolderObj f2 = (FolderObj)d;
                        TreeNode tn_obj = new TreeNode();
                        tn_obj.Name = f2.Key;
                        tn_obj.Text = f2.Display;
                        tn_obj.ImageIndex = 2;
                        tn_obj.SelectedImageIndex = 2;
                        tn_folder.Nodes.Add(tn_obj);
                    }
                    treeView_Folders.Nodes.Add(tn_folder);
                    tn_folder = null;
                }
            }
        }

        private void RefreshReports()
        {
            lb_Reports.Items.Clear();
            lb_Reports.Items.AddRange(reportEngine.ReportNames);
        }

        #endregion

        private void treeView_Folders_AfterSelect(object sender, TreeViewEventArgs e)
        {
            TreeNode selectednode = treeView_Folders.SelectedNode;
            if (selectednode == null)
                return;

            if (selectednode.ImageIndex != 0)
            {
                if (!Close_Current_Control(null))
                    return;
                string folder = selectednode.Parent.Name;
                string key = selectednode.Name;
                object[] data = new object[1];
                FolderDefinition fdef = folderEngine.GetFolderDefinitionByName(folder);

                //data = GlobalObjectsSQL.ExecuteSingleTableRead(null, fdef.TableName, fdef.ValueExp + " = '" + key + "'");
                data = new object[] { key };
                UserControl uc = formEngine.LoadControl(formEngine.GetDefinitionByFolderName(folder).Name, data);
                uc.Dock = DockStyle.Fill;
                splitContainer1.Panel2.Controls.Clear();
                splitContainer1.Panel2.Controls.Add(uc);
            }
            if (selectednode.GetNodeCount(false) == 0 && selectednode.ImageIndex != 0)
            {
                string folder = selectednode.Parent.Name;
                string key = selectednode.Name;
                object[] a = folderEngine.GetSubFolderObjects(folder, key);
                TreeNode tn_folder = null;
                foreach (object c in a)
                {
                    if (c.GetType().Equals(typeof(string)))
                    {
                        tn_folder = new TreeNode();
                        tn_folder.Name = (string)c;
                        tn_folder.Text = (string)c;
                        tn_folder.ImageIndex = 0;
                        tn_folder.SelectedImageIndex = 0;
                    }
                    else if (c.GetType().Equals(typeof(FolderObj[])))
                    {
                        object[] f1 = (object[])c;
                        foreach (object d in f1)
                        {
                            FolderObj f2 = (FolderObj)d;
                            TreeNode tn_obj = new TreeNode();
                            tn_obj.Name = f2.Key;
                            tn_obj.Text = f2.Display;
                            tn_obj.ImageIndex = 2;
                            tn_obj.SelectedImageIndex = 2;
                            tn_folder.Nodes.Add(tn_obj);
                        }
                        treeView_Folders.SelectedNode.Nodes.Add(tn_folder);
                        tn_folder = null;
                    }
                }
            }
        }

        #region Tool Strip Menu

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!Close_Current_Control(null))
                return;
            databaseEngine = null;
            folderEngine = null;
            formEngine = null;

            GlobalSystemSettings.ModelFilePath = null;
            GlobalSystemSettings.DatabaseName = null;
            GlobalSystemSettings.ModelName = null;
            GlobalSystemSettings.SystemFolderPath = null;
            GlobalObjectsSQL.SetConnectionString();
            LogWriter.Close();

            treeView_Folders.Nodes.Clear();
            SetControlsState(false);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void EdgeStatz_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!Close_Current_Control(null))
                e.Cancel = true;
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OptionsDialog options;
            try
            {
                options = new OptionsDialog(databaseEngine, folderEngine);
            }
            catch (ArgumentNullException ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            switch (options.ShowDialog())
            {
                case DialogResult.Cancel:
                    break;
                case DialogResult.OK:
                    RefreshTreeNodes();
                    break;
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new AboutEdgeStatz().Show();
        }
        #endregion

        #region ToolBar Items

        private void tsb_Item_Add_Click(object sender, EventArgs e)
        {
            TreeNode selectednode = treeView_Folders.SelectedNode;
            if (selectednode == null)
                return;
            if (selectednode.ImageIndex != 0)
                selectednode = selectednode.Parent;
            string folder = selectednode.Name;
            string parentKey = selectednode.Parent != null ? selectednode.Parent.Name : null;

            UserControl uc = formEngine.LoadControl(formEngine.GetDefinitionByFolderName(folder).Name);
            uc.Dock = DockStyle.Fill;
            ((GeneratedForm)uc).ParentKey = parentKey;
            splitContainer1.Panel2.Controls.Clear();
            splitContainer1.Panel2.Controls.Add(uc);
        }

        private void tsb_Item_Delete_Click(object sender, EventArgs e)
        {
            TreeNode selectednode = treeView_Folders.SelectedNode;
            if (selectednode == null)
                return;
            if (selectednode.ImageIndex == 0)
                return;
            string folder = selectednode.Parent.Name;
            string key = selectednode.Name;

            if (MessageBox.Show("Are you sure you want to permanently delete the " + folder + " item \"" + selectednode.Text + "\"?" + 
                "\n\nThis action will also delete any sub folder items.\nThis action cannot be undone.",
                "Confirm Action", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                try
                {
                    folderEngine.RemoveFolderObject(folder, key);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("The Delete has failed:\nThe most likely cause, is that the item has dependancies \n" + 
                        "(i.e. It is in use by a non-subfolder item). The dependent items must be removed first.\n\n" +
                        ex.GetType().ToString() + ":\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                splitContainer1.Panel2.Controls.Clear();
                RefreshTreeNodes();
            }                     
        }

        private void tsb_Control_Save_Click(object sender, EventArgs e)
        {
            if (splitContainer1.Panel2.Controls.Count > 0)
            {
                GeneratedForm gf = (GeneratedForm)splitContainer1.Panel2.Controls[0];
                try
                {
                    gf.Save();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("An Error has occured during Save operation:\n" + ex.GetType().ToString() +
                        ":\n\t" + ex.Message + "\n\t" + ex.InnerException, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                List<string> path = new List<string> { };
                TreeNode tn = treeView_Folders.SelectedNode;
                while (tn.Parent != null)
                {
                    path.Insert(0, tn.Text);
                    tn = tn.Parent;
                }
                path.Insert(0, tn.Text);
                RefreshTreeNodes();
                TreeNodeCollection tnc = treeView_Folders.Nodes;
                int i = 0;
                while(tnc != null)
                {
                    bool found = false;
                    foreach (TreeNode node in tnc)
                    {
                        if (path[i].ToLower().Trim().Equals(node.Text.ToLower().Trim()))
                        {
                            treeView_Folders.SelectedNode = node;
                            tnc = node.Nodes;
                            i++;
                            found = true;
                            break;
                        }
                    }
                    if (i == path.Count || ! found)
                        tnc = null;
                }
                if (treeView_Folders.SelectedNode != null)
                    treeView_Folders.SelectedNode.Expand();
            }
        }

        private void tsb_Control_Cancel_Click(object sender, EventArgs e)
        {
            Close_Current_Control(sender);
        }

        private bool Close_Current_Control(object sender)
        {
            if (splitContainer1.Panel2.Controls.Count > 0)
            {
                GeneratedForm gf;
                try
                {
                    gf = (GeneratedForm)splitContainer1.Panel2.Controls[0];
                }
                catch (InvalidCastException ex)
                { return true; }
                if (gf.ChangesPending())
                {
                    if (sender == null && databaseEngine.Option_Save_Auto)
                    {
                        try { gf.Save(); }
                        catch (Exception ex)
                        {
                            MessageBox.Show("An Error has occured during save operation:\n" + ex.GetType().ToString() +
                                ":\n\t" + ex.Message + "\n\t" + ex.InnerException, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                    }
                    else if (databaseEngine.Option_Save_Request)
                    {
                        DialogResult rslt = MessageBox.Show("Save Changes to item?", "Save Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                        if (rslt == DialogResult.Yes)
                        {
                            try { gf.Save(); }
                            catch (Exception ex)
                            {
                                MessageBox.Show("An Error has occured during Save operation:\n" + ex.GetType().ToString() +
                                    ":\n\t" + ex.Message + "\n\t" + ex.InnerException, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return false;
                            }
                        }
                        else if (rslt == DialogResult.Cancel)
                        { return false; }
                    }
                }
            }
            if (sender == null)
                return true;
            treeView_Folders.SelectedNode = null;
            splitContainer1.Panel2.Controls.Clear();
            return true;
        }

        #endregion

        #region Import & Export
        private void tsb_Export_Click(object sender, EventArgs e)
        {
            TreeNode selectednode = treeView_Folders.SelectedNode;
            List<TableData> data = new List<TableData> { };
            if(selectednode == null)
                return;

            if (selectednode.ImageIndex != 0)
            {
                string folder = selectednode.Parent.Name;
                string key = selectednode.Name;
                data.AddRange(GetExportData(folder, key, databaseEngine.Options_Recursive));
                LogWriter.WriteToLog("Export Item [" + folder + "] - key {" + key + "}", LogType.Activity);
                
            }else{
                string folder = selectednode.Name;
                foreach (TreeNode tn in selectednode.Nodes)
                {
                    string key = tn.Name;
                    data.AddRange(GetExportData(folder, key, databaseEngine.Options_Recursive));
                    LogWriter.WriteToLog("Export Item [" + folder + "] - key {" + key + "}", LogType.Activity);
                }
            }
            if (data.Count > 0)
            {
                SaveFileDialog sfdialog = new SaveFileDialog();
                sfdialog.Title = "Save Data Dialog";
                sfdialog.Filter = "EdgeStatz Data|*.esd|XML|*.xml|All files|*.*";
                if (sfdialog.ShowDialog() == DialogResult.OK)
                {
                    DataEngine.Export(RemoveDuplicates(data.ToArray()), sfdialog.FileName);
                }
            }
        }

        private TableData[] GetExportData(string folder, string key, bool recursive)
        {
            List<TableData> data = new List<TableData> { };
            GenericFolderDefinition fdef = folderEngine.GetFolderDefinitionByName(folder);
            if(fdef == null)
                fdef = folderEngine.GetEnumDefinitionByName(folder);
            TableDefinition tdef = databaseEngine.GetTableByName(fdef.TableName); 
            string id_col = fdef.ValueExp;

            object[] querydata = GlobalObjectsSQL.ExecuteSingleTableRead(tdef.GetColumnNames(), tdef.Name, 
                (id_col == null || key == null)? key : id_col + " = '" + key + "'");
            TableData temp_data = new TableData(tdef.Name, tdef.GetColumnNames(), tdef.GetColumnTypes());
            foreach(object obj in querydata)
            {
                temp_data.AddRow((object[])obj);

                for (int i = 0; i < tdef.ColumnCount; i++)
                {
                    if (tdef.ColumnArray[i].ForeignKey != null &&
                        ((object[])obj).GetValue(i).GetType() != typeof(DBNull))
                    {
                        TableDefinition foreign_tdef = databaseEngine.GetTableByName(tdef.ColumnArray[i].ForeignKey.Table);
                        GenericFolderDefinition foreign_fdef = folderEngine.GetFolderDefinitionByTable(foreign_tdef.Name);
                        if (foreign_fdef == null)
                            foreign_fdef = folderEngine.GetEnumDefinitionByTable(foreign_tdef.Name);

                        object[] decrypt_val = FolderEngine.DecryptDisplayCode(foreign_fdef.ValueExp, foreign_tdef.Name);
                        object[] foreign_qdata = GlobalObjectsSQL.ExecuteSingleTableRead(new string[] { (string)decrypt_val[0] },
                            "[" + foreign_tdef.Name + "]" + (string)decrypt_val[1], "[" + foreign_tdef.Name + "].[" + tdef.ColumnArray[i].ForeignKey.Column + "] = '" + ((object[])obj).GetValue(i).ToString() + "'");

                        foreach (object obj2 in foreign_qdata)
                            data.AddRange(GetExportData(foreign_fdef.Name, ((object[])obj2).GetValue(0).ToString(), false));
                    }
                }
            }
            data.Add(temp_data);

            if (recursive)
            {
                foreach (SubFolderDefinition sfd in ((FolderDefinition)fdef).SubFolders)
                {
                    FolderDefinition sub_fdef = folderEngine.GetFolderDefinitionByName(sfd.Name);
                    if (sub_fdef.Level == FolderLevel.Four)
                    {
                        data.AddRange(GetExportData(sub_fdef.Name, "[" + sub_fdef.TableName + "].[" + sfd.Column + "] = '" + key + "'", false));
                    }
                    else
                    {
                        object[] sub_qdata = GlobalObjectsSQL.ExecuteSingleTableRead(new string[] { sub_fdef.TableName + "." + sub_fdef.ValueExp },
                                sub_fdef.TableName + " join " + fdef.TableName + " on " + fdef.TableName + "." + sfd.ForeignColumn + "=" + sub_fdef.TableName + "." + sfd.Column,
                                fdef.TableName + "." + id_col + " = '" + key + "'");
                        foreach (object obj3 in sub_qdata)
                        {
                            data.AddRange(GetExportData(sub_fdef.Name, ((object[])obj3).GetValue(0).ToString(), recursive));
                        }
                    }
                }
            }
            return data.ToArray();
        }

        private TableData[] RemoveDuplicates(TableData[] value)
        {
            List<TableData> data = new List<TableData> { };
            for (int i = 0; i < value.Length; i++)
            {
                bool exists = false;
                for (int j = 0; j < data.Count; j++)
                {
                    if (value[i].Name.ToLower().Equals(data[j].Name.ToLower()))
                    {
                        exists = true;
                        foreach (RowData rd in value[i].Rows)
                        {
                            if (!data[j].RowExists(rd.Items))
                                data[j].AddRow(rd.Items);
                        }
                    }
                }
                if (!exists)
                    data.Add(value[i]);
            }
            return data.ToArray();
        }

        private void importToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofdialog = new OpenFileDialog();
            ofdialog.Title = "Import Data";
            ofdialog.Filter = "EdgeStatz Data|*.esd|XML|*.xml|All files|*.*";
            ofdialog.Multiselect = false;
            if (ofdialog.ShowDialog() == DialogResult.OK)
            {
                TableData[] data = DataCheck(DataEngine.Import(ofdialog.FileName));

                foreach (TableData td in data)
                {                
                    foreach (RowData rd in td.Rows)
                    {
                        GlobalObjectsSQL.ExecuteSingleRowInsert(td.Name, td.ColumnNames, rd.Items, null);
                    }
                }
            }
            RefreshTreeNodes();
        }

        private TableData[] DataCheck(TableData[] data)
        {
            for (int i = 0; i < data.Length;i++ )
            {
                string valueExp = null;
                string displayExp = null;
                string tableExp = null;
                int id_col;
                TableDefinition tdef = databaseEngine.GetTableByName(data[i].Name);
                GenericFolderDefinition fdef = folderEngine.GetFolderDefinitionByTable(data[i].Name);
                if (fdef == null)
                    fdef = folderEngine.GetEnumDefinitionByTable(data[i].Name);
                if (fdef == null)
                { MessageBox.Show("Table {" + data[i].Name + "} could not be found in the model.\nThis table import will be skipped."); continue; }

                id_col = data[i].ColumnIndex(fdef.ValueExp);
                valueExp = fdef.ValueExp;
                displayExp = fdef.DisplayExp;

                tableExp = fdef.TableName;

                for (int j = 0; j < data[i].Rows.Length;j++ )
                {
                    if (valueExp == null || displayExp == null)
                    {
                        valueExp = "";
                        for (int k = 0; k < tdef.ColumnCount; k++)
                        {
                            if (tdef.ColumnArray[k].PrimaryKey)
                            {
                                if (valueExp.Length > 0)
                                    valueExp += " AND ";
                                valueExp += tdef.ColumnArray[k].Name + " = " + GlobalObjectsSQL.ReturnForDataEntry(data[i].GetItem(k, tdef.ColumnArray[k].Name));
                            }
                        }
                        if (GlobalObjectsSQL.ExecuteSingleTableRead(null, data[i].Name, valueExp).Length > 0)
                        {
                            LogWriter.WriteToLog("Import: Item already exists: [" + fdef.Name + "] - " + valueExp, LogType.Activity);
                            data[i].SetNullRow(j);
                        }
                        continue;
                    }
                    object[] obj = GlobalObjectsSQL.ExecuteSingleTableRead(null, data[i].Name,
                        valueExp + " = " + DataEngine.GetExpression(data[i], j, valueExp));
                    if (obj.Length > 0)
                    {
                        LogWriter.WriteToLog("Import: Item already exists: [" + fdef.Name + "] - " + valueExp + 
                            " = {" + data[i].Rows[j].Items[id_col].ToString() + "}", LogType.Activity);
                        data[i].SetNullRow(j);
                    }
                    else
                    {
                        object[] decrypt_disp = FolderEngine.DecryptDisplayCode(displayExp, tableExp);
                        object[] decrypt_val = FolderEngine.DecryptDisplayCode(valueExp, tableExp);

                        object[] obj2 = GlobalObjectsSQL.ExecuteSingleTableRead(new string[] { (string)decrypt_val[0], (string)decrypt_disp[0] },
                            tableExp + " " + (string)decrypt_disp[1] + (string)decrypt_val[1], (string)decrypt_disp[0] + " = " +
                            DataEngine.GetExpression(data[i], data[i].Rows[j], displayExp));
                        if (obj2.Length > 0)
                        {
                            obj2 = (object[])obj2[0];
                            DialogResult drslt = MessageBox.Show("Item " + data[i].Name.ToUpper() + " - '" +
                                obj2[1] + "' already exists but with a different ID." +
                                "\n\nWould you like the import items ID to be changed to the existing one?" +
                                "\n\nSelecting no will add the import item as is (possibly creating a duplicate)," +
                                "\nSelecting Yes will skip the current item and change any references" +
                                " in the import data to the existing ID", "Info",
                                MessageBoxButtons.YesNo, MessageBoxIcon.Information);
                            LogWriter.WriteToLog("Import: Possible Duplicate: [" + fdef.Name + "] - " + displayExp +
                                " = '" + obj2[1].ToString() + "'", LogType.Activity);

                            if (drslt == DialogResult.Yes)
                            {
                                for (int l = 0; l < data.Length; l++)
                                    if (i != l)
                                        data[l].ReplaceGuid(new Guid(data[i].Rows[j].Items[id_col].ToString()), new Guid(obj2[0].ToString()));

                                LogWriter.WriteToLog("Import: Replace Guid: Old {" + data[i].Rows[j].Items[id_col].ToString() +
                                    "} - New {" + obj2[0].ToString() + "}", LogType.Activity);
                                data[i].SetNullRow(j);
                            }
                            else if (drslt == DialogResult.No)
                                LogWriter.WriteToLog("Import: Item Added: folder [" + fdef.Name +
                                    "] - Key {" + data[i].Rows[j].Items[id_col].ToString() + "}", LogType.Activity);
                        }
                        else
                            LogWriter.WriteToLog("Import: Item Added: folder [" + fdef.Name +
                                    "] - Key {" + data[i].Rows[j].Items[id_col].ToString() + "}", LogType.Activity);
                    }
                }
                data[i].RemoveNullRows();
            }
            return data;
        }

        private void selectionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tsb_Export_Click(sender, e);
        }

        private void enumsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            EnumFolderDefinition[] efdefs = folderEngine.GetEnumFolderDefinitions();
            List<TableData> data = new List<TableData> { };
            foreach (EnumFolderDefinition efdef in efdefs)
            {
                TableDefinition tdef = databaseEngine.GetTableByName(efdef.TableName);
                TableData temp_data = new TableData(tdef.Name, tdef.GetColumnNames(), tdef.GetColumnTypes());
                object[] obj = GlobalObjectsSQL.ExecuteSingleTableRead(tdef.GetColumnNames(), tdef.Name, "");
                foreach (object obj2 in obj)
                {
                    temp_data.AddRow((object[])obj2);
                }
                if (temp_data.Rows.Length > 0)
                    data.Add(temp_data);
            }
            if (data.Count > 0)
            {
                SaveFileDialog sfdialog = new SaveFileDialog();
                sfdialog.Title = "Save Data Dialog";
                sfdialog.Filter = "EdgeStatz Data|*.esd|XML|*.xml|All files|*.*";
                sfdialog.DefaultExt = "xml";
                if (sfdialog.ShowDialog() == DialogResult.OK)
                {
                    DataEngine.Export(RemoveDuplicates(data.ToArray()), sfdialog.FileName);
                }
            }            
        }

        private void allDataToolStripMenuItem_Click(object sender, EventArgs e)
        {
            List<TableData> data = new List<TableData> { };

            EnumFolderDefinition[] efdefs = folderEngine.GetEnumFolderDefinitions();
            foreach (EnumFolderDefinition efdef in efdefs)
            {
                TableDefinition tdef = databaseEngine.GetTableByName(efdef.TableName);
                TableData temp_data = new TableData(tdef.Name, tdef.GetColumnNames(), tdef.GetColumnTypes());
                object[] obj = GlobalObjectsSQL.ExecuteSingleTableRead(tdef.GetColumnNames(), tdef.Name, "");
                foreach (object obj2 in obj)
                {
                    temp_data.AddRow((object[])obj2);
                }
                if (temp_data.Rows.Length > 0)
                    data.Add(temp_data);
            }
            foreach (TreeNode root in treeView_Folders.Nodes)
            {
                string folder = root.Name;
                foreach (TreeNode tn in root.Nodes)
                {
                    string key = tn.Name;
                    data.AddRange(GetExportData(folder, key, true));
                }
            }

            if (data.Count > 0)
            {
                SaveFileDialog sfdialog = new SaveFileDialog();
                sfdialog.Title = "Save Data Dialog";
                sfdialog.Filter = "EdgeStatz Data|*.esd|XML|*.xml|All files|*.*";
                sfdialog.DefaultExt = "xml";
                if (sfdialog.ShowDialog() == DialogResult.OK)
                {
                    DataEngine.Export(RemoveDuplicates(data.ToArray()), sfdialog.FileName);
                }
            }            
        }
        #endregion

        #region ReportViewer

        void lb_Reports_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            if (lb_Reports.SelectedItem == null)
                return;
            string report_name = (string)lb_Reports.SelectedItem;
            ES_R_Report report = reportEngine.GetReport(report_name);
            string report_path = report.Path;
            for (int i = 0; i < report.ReportParameters.Count; i++)
                report.ReportParameters[i].Value = null;

            reportViewer1.Reset();
            reportViewer1.ProcessingMode = Microsoft.Reporting.WinForms.ProcessingMode.Local;
            reportViewer1.LocalReport.EnableHyperlinks = true;
            reportViewer1.LocalReport.ReportPath = report_path;

            ParametersDisplay display = new ParametersDisplay(report);
            display.ParameterInfo = reportViewer1.LocalReport.GetParameters();
            if (display.ShowDialog() == DialogResult.OK)
            {
                ES_R_ReportParameter[] updated_param = display.Parameters;
                for (int i = 0; i < updated_param.Length; i++)
                    report.ReportParameters[i].Value = updated_param[i].Value;
            }
            else { return; }
            
            foreach (string ds2r in report.DataSetsToRun)
            {
                ReportDataSource ds = new ReportDataSource(ds2r);
                ds.Value = report.GetTableForDataSet(ds2r);
                reportViewer1.LocalReport.DataSources.Add(ds);
            }
            try
            {
                foreach (ReportParameterInfo rpi in reportViewer1.LocalReport.GetParameters())
                    foreach (ES_R_ReportParameter rp in report.ReportParameters)
                        if(rpi.Name.ToLower().Equals(rp.Name.ToLower()))
                            reportViewer1.LocalReport.SetParameters(new ReportParameter(rp.Name, rp.Label == null ? null : rp.Label.ToString()));
            }
            catch (LocalProcessingException ex)
            {
                MessageBox.Show(ex.Message + "\n" + ex.InnerException, ex.GetType().ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            reportViewer1.RefreshReport();
        }
        
        private void tsb_ReportsView_Click(object sender, EventArgs e)
        {
            tsb_ReportsView.Enabled = false;
            tsb_TreeView.Enabled = true;
            tsb_Item_Add.Enabled = false;
            tsb_Item_Delete.Enabled = false;
            tsb_Export.Enabled = false;
            tsb_Control_Save.Enabled = false;
            tsb_Control_Cancel.Enabled = false;

            this.splitContainer1.Panel1.Controls.Clear();
            this.splitContainer1.Panel2.Controls.Clear();

            this.splitContainer1.Panel1.Controls.Add(this.lb_Reports);
            this.splitContainer1.Panel2.Controls.Add(this.reportViewer1);
            lb_Reports_SelectedIndexChanged(null, null);
        }

        private void tsb_TreeView_Click(object sender, EventArgs e)
        {
            tsb_ReportsView.Enabled = true;
            tsb_TreeView.Enabled = false;
            tsb_Item_Add.Enabled = true;
            tsb_Item_Delete.Enabled = true;
            tsb_Export.Enabled = true;
            tsb_Control_Save.Enabled = true;
            tsb_Control_Cancel.Enabled = true;

            this.splitContainer1.Panel1.Controls.Clear();
            this.splitContainer1.Panel2.Controls.Clear();

            this.splitContainer1.Panel1.Controls.Add(this.treeView_Folders);
            treeView_Folders_AfterSelect(null, null);
        }

        private void EdgeStatz_Load(object sender, EventArgs e)
        {
            this.reportViewer1.RefreshReport();
        }

        #endregion
        
        #region Model Install / Delete
        private void installNewToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ModelInstaller installer = new ModelInstaller(ModelInstaller.FUNCTION_INSTALL_NEW);
            if (installer.ShowDialog() == DialogResult.OK)
            {
                LoadModelFile(installer.ModelPath);
                if (installer.ImportTables != null)
                {
                    TableData[] data = DataCheck(installer.ImportTables);
                    foreach (TableData td in data)
                        foreach (RowData rd in td.Rows)
                            GlobalObjectsSQL.ExecuteSingleRowInsert(td.Name, td.ColumnNames, rd.Items, null);
                    RefreshTreeNodes();
                }
            }
        }

        private void deleteExistingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (GlobalSystemSettings.ModelFilePath != null)
            {
                if (MessageBox.Show("Continuing into the delete model dialog will close the currently opened model.\nDo you want to continue?",
                    "Close Model File", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    closeToolStripMenuItem_Click(null, e);
                else
                    return;
            }
            ModelInstaller installer = new ModelInstaller(ModelInstaller.FUNCTION_DELETE_EXISTING);
            installer.ShowDialog();
        }
        #endregion
        
        private void SetControlsState(bool enable)
        {
            tsb_TreeView_Click(null, null);
            closeToolStripMenuItem.Enabled = enable;
            importToolStripMenuItem.Enabled = enable;
            exportToolStripMenuItem.Enabled = enable;
            tsb_Item_Add.Enabled = enable;
            tsb_Item_Delete.Enabled = enable;
            tsb_Export.Enabled = enable;
            tsb_Control_Save.Enabled = enable;
            tsb_Control_Cancel.Enabled = enable;
            tsb_ReportsView.Enabled = enable;
            optionsToolStripMenuItem.Enabled = enable;
        }
    }
}
